/*
 *    Copyright © OpenAtom Foundation.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package com.inspur.edp.bef.builtincomponents.SecretLevel;

import com.inspur.edp.bef.api.action.validation.IValidationContext;
import com.inspur.edp.bef.api.be.BEInfo;
import com.inspur.edp.bef.core.determination.QueryDeterminationContext;
import com.inspur.edp.bef.spi.action.validation.AbstractValidation;
import com.inspur.edp.cef.entity.changeset.AbstractModifyChangeDetail;
import com.inspur.edp.cef.entity.changeset.IChangeDetail;
import com.inspur.edp.cef.entity.entity.IValuesContainer;
import com.inspur.edp.cef.spi.entity.info.propertyinfo.DataTypePropertyInfo;
import com.inspur.edp.cef.spi.entity.info.propertyinfo.ObjectType;
import com.inspur.edp.cef.spi.entity.resourceInfo.builinImpls.CefEntityResInfoImpl;
import io.iec.edp.caf.commons.exception.CAFRuntimeException;
import io.iec.edp.caf.commons.exception.ExceptionLevel;
import io.iec.edp.caf.commons.utils.SpringBeanUtils;
import io.iec.edp.caf.sys.security.api.data.SecLevelObjSet;
import io.iec.edp.caf.sys.security.api.data.SecurityLevel;
import io.iec.edp.caf.sys.security.api.manager.SecurityLevelMapManager;
import io.iec.edp.caf.sys.security.api.manager.SecurityRuntimeManager;

import java.util.List;
import java.util.ArrayList;
import java.util.Map;

public class SecretValidator extends AbstractValidation {
    static SecurityRuntimeManager securityRuntimeManager = SpringBeanUtils.getBean(SecurityRuntimeManager.class);
    private final SecurityLevelMapManager securityLevelMapManager = null;
    private List<SecurityLevel> canAccessSecLevels;
    //密级字段
//    private String secretPropName;
    private SecetLevelObjSetInfo secetLevelObjSetInfo;
    /**
     * 新实例初始化AbstractValidation具有给定的校验规则上下文，以及实体数据变更集
     *
     * @param context 校验规则上下文
     * @param change  实体数据变更集
     */
    protected SecretValidator(IValidationContext context, IChangeDetail change) {
        super(context, change);
    }

    @Override
    protected void execute() {
        String beId =getContext().getBEManagerContext().getBEManager().getBEInfo().getBEID();
        if(beId==null||beId.equals(""))
            return;
        SecLevelObjSet secLevelObjSet = securityRuntimeManager.getSecLevelObjByBEId(getContext().getBEManagerContext().getBEManager().getBEInfo().getBEID());
        if(secLevelObjSet == null)
            return;
        secetLevelObjSetInfo = SecretUtil.getSecretLevelObjSetInfo(secLevelObjSet);
        if(secetLevelObjSetInfo.getFieldName() == null || secetLevelObjSetInfo.getFieldName().length() == 0){
            return;
        }
        DataTypePropertyInfo secPropInfo = getSecretPropertyInfo(secetLevelObjSetInfo.getFieldName());
        if(secPropInfo == null){
            return;
        }
        if(secPropInfo.getObjectType() == ObjectType.UDT)
            return;
        canAccessSecLevels = securityRuntimeManager.getCanAccessSecLevelsByBE(getContext().getBEManagerContext().getBEManager().getBEInfo().getBEID());
//        secretPropName = secLevelObjSet.getSecLevelIdField();
        switch (this.getChange().getChangeType()) {
            case Added:
                checkUserCanAdd();
                break;
            case Modify:
                checkUserCanModify();
                break;
            case Deleted:
                checkUserCanDelete();
                break;
            default:
                break;
        }
    }

    private DataTypePropertyInfo getSecretPropertyInfo(String fieldName){
        DataTypePropertyInfo dataTypePropertyInfo = null;
        //rootEntityResInfo
        CefEntityResInfoImpl cefEntityResInfo = (CefEntityResInfoImpl) getContext().getModelResInfo().getCustomResource(getContext().getNodeCode());
        for(Map.Entry<String, DataTypePropertyInfo> propertyInfoEntry : cefEntityResInfo.getEntityTypeInfo().getPropertyInfos().entrySet()){
            if(propertyInfoEntry.getKey().equals(fieldName)){
                return propertyInfoEntry.getValue();
            }
        }

        return dataTypePropertyInfo;
    }

    private void checkUserCanAdd() {
        //todo 调用接口获取当前用户有权限的密级集合
//        List<SecurityLevel> secrets = securityRuntimeManager.getCanAccessSecLevelsByBE(getContext().getBEManagerContext().getBEManager().getBEInfo().getBEID());
        String secvalue = getSecValue();
        SecurityLevel securityLevel = null;
        switch (secetLevelObjSetInfo.getFieldType()){
            case "secLevelIdField":
                securityLevel = canAccessSecLevels.stream().filter(a->a.getId().equals(secvalue)).findFirst()
                        .orElse(null);
                break;
            case "secLevelField":
                securityLevel = canAccessSecLevels.stream().filter(a->a.getSecLevel().toString().equals(secvalue)).findFirst()
                        .orElse(null);
                break;
            case "secLevelNameField":
                securityLevel = canAccessSecLevels.stream().filter(a->a.getName().equals(secvalue)).findFirst()
                        .orElse(null);
                break;
        }

        if(secvalue !=null && !secvalue.isEmpty() && securityLevel == null){
            if(secetLevelObjSetInfo.getFieldType() == "secLevelField" && "0".equals(secvalue)){
                return;
            }
            throw new CAFRuntimeException("", "5202", "用户密级权限不足，请修改密级级别！", null, ExceptionLevel.Warning, true);
        }
    }

    private boolean checkCanAccess(String value){

        return false;
    }

    private void checkUserCanModify() {
        //todo 调用接口获取当前用户有权限的密级集合
        AbstractModifyChangeDetail modifyChangeDetail = (AbstractModifyChangeDetail) getChange();
        if(modifyChangeDetail.getPropertyChanges().containsKey(secetLevelObjSetInfo.getFieldName())){
            String secvalue = getSecValue();

            SecurityLevel securityLevel = null;
            switch (secetLevelObjSetInfo.getFieldType()){
                case "secLevelIdField":
                    securityLevel = canAccessSecLevels.stream().filter(a->a.getId().equals(secvalue)).findFirst()
                            .orElse(null);
                    break;
                case "secLevelField":
                    securityLevel = canAccessSecLevels.stream().filter(a->a.getSecLevel().toString().equals(secvalue)).findFirst()
                            .orElse(null);
                    break;
                case "secLevelNameField":
                    securityLevel = canAccessSecLevels.stream().filter(a->a.getName().equals(secvalue)).findFirst()
                            .orElse(null);
                    break;
            }

            if(secvalue !=null && !secvalue.isEmpty() && securityLevel == null){
                if(secetLevelObjSetInfo.getFieldType() == "secLevelField" && "0".equals(secvalue)){
                    return;
                }
                throw new CAFRuntimeException("", "5202", "用户密级权限不足，请修改密级级别！", null, ExceptionLevel.Warning, true);
            }
        }
    }

    private String getSecValue(){
        Object secObj = getContext().getData().getValue(secetLevelObjSetInfo.getFieldName());
        if(secObj == null)
            return "";
        String secvalue;
        if(secObj instanceof IValuesContainer){
            secvalue = ((IValuesContainer)secObj).getValue(secetLevelObjSetInfo.getFieldName()).toString();
        }
        else {
            secvalue = secObj.toString();
        }
        return secvalue;
    }

    private void checkUserCanDelete() {
        //todo 调用接口获取当前用户有权限的密级集合
        Object secObj = this.getContext().getOriginalData().getValue(secetLevelObjSetInfo.getFieldName());
        if(secObj == null)
            throw new RuntimeException("未获取到被删除数据的密级级别");
        final String secvalue;
        if(secObj instanceof IValuesContainer){
            secvalue = ((IValuesContainer)secObj).getValue(secetLevelObjSetInfo.getFieldName()).toString();
        }
        else {
            secvalue = secObj.toString();
        }
        SecurityLevel securityLevel = null;
        switch (secetLevelObjSetInfo.getFieldType()){
            case "secLevelIdField":
                securityLevel = canAccessSecLevels.stream().filter(a->a.getId().equals(secvalue)).findFirst()
                        .orElse(null);
                break;
            case "secLevelField":
                securityLevel = canAccessSecLevels.stream().filter(a->a.getSecLevel().toString().equals(secvalue)).findFirst()
                        .orElse(null);
                break;
            case "secLevelNameField":
                securityLevel = canAccessSecLevels.stream().filter(a->a.getName().equals(secvalue)).findFirst()
                        .orElse(null);
                break;
        }
        if(secvalue !=null && !secvalue.isEmpty() && securityLevel == null){
            if(secetLevelObjSetInfo.getFieldType() == "secLevelField" && "0".equals(secvalue)){
                return;
            }
            throw new CAFRuntimeException("", "5202", "用户密级权限不足，请修改密级级别！", null, ExceptionLevel.Warning, true);
        }
    }

    private List<SecurityLevel> getCanAccessSecLevelsByBE(){
        return securityRuntimeManager.getCanAccessSecLevelsByBE(getContext().getBEManagerContext().getBEManager().getBEInfo().getBEID());
    }
}
